package com.heima.datastructure.circular;

import java.util.Iterator;
import java.util.function.Consumer;

/**
 * 环形链表
 */
public class DoublyLinkedListSentinel implements Iterable<Integer> {

    /**
     * 哨兵节点
     */
    private final Node sentinel; // 哨兵是环形中的一个节点

    /**
     * 节点类
     */
    private static class Node{
        Node next;
        int value;
        Node prev;
        public Node(Node next, int value, Node prev) {
            this.next = next;
            this.value = value;
            this.prev = prev;
        }
    }

    /**
     * 利用无参构造初始化循环链表
     */
    public DoublyLinkedListSentinel() {
        this.sentinel = new Node(null,-1,null);
        sentinel.next = sentinel;
        sentinel.prev = sentinel;
    }


    /**
     * 递归遍历链表
     * @param before 递的时候要做的事情
     * @param after  归的时候要做的事情
     */
    public void loop3(Consumer<Integer> before, Consumer<Integer> after){
        recursion(sentinel.next,before,after);
    }

    /**
     * 递归遍历链表
     * @param curr 当前节点
     * @param before 递的时候要做的事情
     * @param after  归的时候要做的事情
     */
    private void recursion(Node curr, Consumer<Integer> before, Consumer<Integer> after){
        if (curr == sentinel){
            return;
        }
        before.accept(curr.value);
        recursion(curr.next,before,after);
        after.accept(curr.value);
    }


    /**
     * 迭代器遍历
     * @return 迭代器
     */
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            Node p = sentinel.next;
            @Override
            public boolean hasNext() {
                return p != sentinel;
            }

            @Override
            public Integer next() {
                int value = p.value;
                p = p.next;
                return value;
            }
        };
    }

    /**
     * 异常处理
     * @param index 非法的索引
     * @return 非法参数的异常
     */
    public IllegalArgumentException illegalIndex(int index){
        return new IllegalArgumentException(
                String.format("index [%d] 不合法",index)
        );
    }

    /**
     * 异常处理
     * @param index 非法的索引
     * @param ex 自定义的异常提示信息
     * @return 非法参数的异常
     */
    public IllegalArgumentException illegalIndex(int index, String ex){
        return new IllegalArgumentException(
                String.format("index [%d] 不合法，%s",index,ex)
        );
    }

    /**
     * 第一个位置添加节点
     * @param value 节点的值
     */
    public void addFirst(int value){
        Node head = sentinel;
        Node next = sentinel.next;
        Node added = new Node(next, value, head);
        head.next = added;
        next.prev = added;
    }

    /**
     * 最后一个位置添加节点
     * @param value 节点的值
     */
    public void addLast(int value){
        Node prev = sentinel.prev;
        Node next = sentinel;
        Node added = new Node(next, value, prev);
        prev.next = added;
        next.prev = added;
    }

    /**
     * 删除第一个节点
     * @return 删除节点的值
     */
    public int removeFirst(){
        Node removed = sentinel.next;
        if (removed == sentinel){
            throw illegalIndex(0,"链表为空");
        }
        Node prev = sentinel;
        Node next = removed.next;
        int value = removed.value;

        prev.next = next;
        next.prev = prev;
        return value;
    }

    /**
     * 删除最后一个节点
     * 删除节点的值
     */
    public int removeLast(){
        Node removed = sentinel.prev;
        if (removed == sentinel){
            throw illegalIndex(0,"链表为空");
        }
        Node prev = removed.prev;
        Node next = sentinel;
        int value = removed.value;

        prev.next = next;
        next.prev = prev;
        return value;
    }

    /**
     * 根据索引查找节点
     * @param index 索引
     * @return 节点
     */
    private Node findNode(int index){
        int i = 0;
        for (Node p = sentinel.next; p != sentinel; p = p.next, i++){
            if (index == i){
                return p;
            }
        }
        return null;
    }

    /**
     * 根据值查找节点
     * @param value 值
     * @return 找到的节点
     */
    private Node findByValue(int value){
        for (Node p = sentinel.next; p != sentinel; p = p.next){
            if (p.value == value){
                return p;
            }
        }
        return null;
    }

    /**
     * 根据值地喊出节点
     * @param value 值
     */
    public void removeByValue(int value){
        Node removed = findByValue(value);
        if (removed == null){
            throw new IllegalArgumentException(
                    String.format("value [%d] 不合法",value)
            );
        }
        Node prev = removed.prev;
        Node next = removed.next;
        prev.next = next;
        next.prev = prev;
    }

    /**
     * 根据索引找到节点的值
     * @param index 索引
     * @return 节点的值
     */
    public int get(int index){
        Node node = findNode(index);
        if (node == null){
            throw illegalIndex(index);
        }
        return node.value;
    }
}
